#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <time.h>
#include "des.h"

#define SS_PORT 24680

char K_SS[] = "INSS0000"; //由SS和TGS预先商定
char MYID[100] = "Tencent";

void serve(struct sockaddr_in *clientAddr, int client)
{
    int i;
    int iDataNum = -1;
    char E[200]; // 存放由client发送过来的消息E
    char G[200]; // 存放由client发送过来的消息G
    char H[200]; // 发送的加密消息H

    char Ksession_Client_SS[100]; //客户和SS服务器会话的密钥
    char ClientID1[100];//消息中E中的ST的客户的ID
    char ClientID2[100]; //消息G中的客户的ID
    char client_net_addr[100];//客户的网络地址
    time_t timestamp1; //E中的ST的时间戳
    time_t timestamp2; //消息G的时间戳
    time_t timestamp3; //更新的消息的时间戳

    //inet_ntoa ip地址转换函数，将网络字节序IP转换为点分十进制IP
    //表达式：char *inet_ntoa (struct in_addr);
    printf("IP is %s\n", inet_ntoa(clientAddr->sin_addr));
    printf("Port is %d\n", htons(clientAddr->sin_port));
    printf("等待消息...\n");

    printf("开始读取消息E\n");
    int lenOfE = recv(client,E,200,0);
    E[lenOfE] = 0;
    // printf("信息E\n");
    // printBase64(E);
    // printf("\n");

    printf("开始读取信息G\n");
    int lenOfG = recv(client,G,200,0);
    G[lenOfG] = 0;
    // printf("信息G\n");
    // printBase64(G);
    // printf("\n");

    //解密消息E
    printf("解密消息E，消息E包括ServiceID和ST\n");
    char tempST[200];
    char ServiceID[100];
    char ST[200];
    sscanf(E,"%[^,],%s",ServiceID,tempST);
    // printf("tempST is");
    // printBase64(tempST);
    // printf("\n");
    printf("ServiceId is %s\n",ServiceID);
    //防止出现\0 重新赋值
    for(i = strlen(ServiceID)+1 ; i<lenOfE;i++){
        // printf("%d\n",i);
        tempST[i-(strlen(ServiceID)+1)] = E[i];
    }
    tempST[lenOfE-(strlen(ServiceID)+1)] = 0;
    // printf("tempST is");
    // printBase64(tempST);
    // printf("\n");
    rdes(K_SS,tempST,(lenOfE - strlen(ServiceID)-1),ST);
    printf("ST = %s\n",ST);
    sscanf(ST,"<%[^,],%[^,],%ld,%[^>]>",ClientID1,client_net_addr,&timestamp1,Ksession_Client_SS);

    printf("Get Ksession_Client_SS %s\n",Ksession_Client_SS);

    //解密消息G
    printf("解密消息G\n");
    char TrueG[200];
    rdes(Ksession_Client_SS,G,lenOfG,TrueG);
    printf("解密后的G %s\n",TrueG);
    sscanf(TrueG,"<%[^,],%ld>",ClientID2,&timestamp2);

    timestamp3 = timestamp2 + 1;
    // printf("%d",timestamp3);
    // printf("%s\n",ClientID1); 
    // printf("%s\n",ClientID2);
    if((strcmp(ClientID1,ClientID2)!=0)){
        printf("认证失败，ID不匹配\n");
        return;
    }
    else{
        printf("ID匹配成功 验证通过\n");
    }
    printf("生成消息H\n");
    char tempH[200];
    sprintf(tempH,"%s,%ld",ClientID1,timestamp3);
    int lenOfH = des(Ksession_Client_SS,tempH,strlen(tempH),H);
    printf("发送消息H 明文是 %s\n",tempH);
    send(client,H,lenOfH,0);
    printf("发送完成\n");

    printf("----------SS发送消息完成----------\n");
}


int main(int argc, char *argv[])
{
    srand(time(NULL)+1);
    int client;
    int SSSocket;
    pid_t pid;
    int addr_len = sizeof(struct sockaddr_in);
    struct sockaddr_in AServer_addr;

    //socket函数，失败返回-1
    //int socket(int domain, int type, int protocol);
    //第一个参数表示使用的地址类型，一般都是ipv4，AF_INET
    //第二个参数表示套接字类型：tcp：面向连接的稳定数据传输SOCK_STREAM
    //第三个参数设置为0
    if ((SSSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("Create socket error!\n");
        return 1;
    }
    else
    {
        printf("Socket number = %d\n", SSSocket);
    }

    //初始化服务器端的套接字
    bzero(&AServer_addr, sizeof(AServer_addr));
    AServer_addr.sin_family = AF_INET;                //TCP/IP协议
    AServer_addr.sin_port = htons(SS_PORT);           //绑定端口号，htons即host-to-network
    AServer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //服务器接受的任意内外网IP

    if (bind(SSSocket, (struct sockaddr *)&AServer_addr, sizeof(AServer_addr)) < 0)
    {
        perror("connect");
        return 0;
    }
    else
    {
        printf("bind succeed\n");
    }

    listen(SSSocket, 100);
    printf("SS is Listening %d\n", SS_PORT);
    while (1)
    {
        //调用accept函数后，会进入阻塞状态
        //accept返回一个套接字的文件描述符，这样服务器端便有两个套接字的文件描述符，
        //serverSocket和client。
        //serverSocket仍然继续在监听状态，client则负责接收和发送数据
        //clientAddr是一个传出参数，accept返回时，传出客户端的地址和端口号
        //addr_len是一个传入-传出参数，传入的是调用者提供的缓冲区的clientAddr的长度，以避免缓冲区溢出。
        //传出的是客户端地址结构体的实际长度。
        //出错返回-1

        struct sockaddr_in ClientAddr;
        client = accept(SSSocket, (struct sockaddr *)&ClientAddr, (socklen_t *)&addr_len);
        // printf("client is %d\n", client);
        if (client > 0)
        {
            printf("we have a new client\n");
        }
        pid = fork();
        if (pid == 0)
        { //返回子进程
            serve(&ClientAddr, client);
            return 0;
        }
    }
    close(SSSocket);
    return 0;
}









